/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
*                  Equipped with M5Core2 sample source code
*                          配套  M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/module/comx_gsm
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/module/comx_gsm
*
* describe: comx_gsm.
* date: 2021/9/2
*******************************************************************************
  Set the DIP switch to 5 and 13
  and the screen will display the signal strength and network access status
  将 DIP 开关设置为 5 和 13
  并且屏幕会显示信号强度和网络访问状态
 */
#include <M5Core2.h>
#include <stdint.h>
#include <vector>
#include "TFTTerminal.h"

TFT_eSprite Disbuff = TFT_eSprite(&M5.Lcd);
TFT_eSprite TerminalBuff = TFT_eSprite(&M5.Lcd);
TFTTerminal terminal(&TerminalBuff);
TaskHandle_t xhandle_lte_event = NULL;
SemaphoreHandle_t command_list_samap;

typedef enum
{
  kQUERY_MO = 0,
  KTEST_MO,
  kASSIGN_MO,
  kACTION_MO,
  kQUERY_MT,
  kTEST_MT,
  kASSIGN_MT,
  kACTION_MT,
  kINFORM
} LTEMsg_t;

typedef enum
{
  kErrorSendTimeOUT = 0xe1,
  kErrorReError = 0xe2,
  kErroeSendError = 0xe3,
  kSendReady = 0,
  kSending = 1,
  kWaitforMsg = 2,
  kWaitforRead = 3,
  kReOK
} LTEState_t;

struct ATCommand
{
  uint8_t command_type;
  String str_command;
  uint16_t send_max_number;
  uint16_t max_time;
  uint8_t state;
  String read_str;
  uint16_t _send_count;
  uint16_t _send_time_count;

} user;

using namespace std;
vector<ATCommand> serial_at;
String zmmi_str;
void SIM800Task(void *arg)
{
  int Number = 0;
  String restr;
  while (1)
  {
    xSemaphoreTake(command_list_samap, portMAX_DELAY);

    if (Serial2.available() != 0)
    {
      String str = Serial2.readString();
      restr += str;

      if(restr.indexOf("\r\n") != -1)
      {

      }

      if( restr.indexOf("+ZMMI:")!= -1)
      {
        zmmi_str = restr;
      }
      else if ((restr.indexOf("OK") != -1) || (restr.indexOf("ERROR") != -1))
      {
        Serial.print(restr);
        if (restr.indexOf("OK") != -1)
        {
          if ((serial_at[0].command_type == kACTION_MO) || (serial_at[0].command_type == kASSIGN_MO))
          {
            serial_at.erase(serial_at.begin());
            Serial.printf("erase now %d\n", serial_at.size());
          }
          else
          {
            serial_at[0].read_str = restr;
            serial_at[0].state = kWaitforRead;
          }
        }
        else if (restr.indexOf("ERROR") != -1)
        {
          serial_at[0].state = kErrorReError;
        }
        else
        {
        }
        restr.clear();
      }
    }

    if (serial_at.empty() != true)
    {
      Number = 0;
      switch (serial_at[0].state)
      {
      case kSendReady:
        Serial.printf(serial_at[0].str_command.c_str());
        Serial2.write(serial_at[0].str_command.c_str());
        serial_at[0].state = kSending;
        break;
      case kSending:

        if (serial_at[0]._send_time_count > 0)
        {
          serial_at[0]._send_time_count--;
        }
        else
        {
          serial_at[0].state = kWaitforMsg;
        }
        /* code */
        break;
      case kWaitforMsg:
        if (serial_at[0]._send_count > 0)
        {
          serial_at[0]._send_count--;
          serial_at[0]._send_time_count = serial_at[0].max_time;
          Serial.printf(serial_at[0].str_command.c_str());
          Serial2.write(serial_at[0].str_command.c_str());
          restr.clear();
          serial_at[0].state = 1;
        }
        else
        {
          serial_at[0].state = kErrorSendTimeOUT;
        }
        /* code */
        break;
      case kWaitforRead:
        /* code */
        break;
      case 4:
        /* code */
        break;
      case kErrorSendTimeOUT:
        /* code */
        break;
      case 0xe2:
        /* code */
        break;
      default:
        break;
      }
    }
    xSemaphoreGive(command_list_samap);
    delay(10);
  }
}

void AddMsg(String str, uint8_t type, uint16_t sendcount, uint16_t sendtime)
{
  struct ATCommand newcommand;
  newcommand.str_command = str;
  newcommand.command_type = type;
  newcommand.max_time = sendtime;
  newcommand.send_max_number = sendcount;
  newcommand.state = 0;
  newcommand._send_count = sendcount;
  newcommand._send_time_count = sendtime;
  xSemaphoreTake(command_list_samap, portMAX_DELAY);
  serial_at.push_back(newcommand);
  xSemaphoreGive(command_list_samap);
}

uint8_t readSendState(uint32_t number)
{
  xSemaphoreTake(command_list_samap, portMAX_DELAY);
  uint8_t restate = serial_at[number].state;
  xSemaphoreGive(command_list_samap);
  return restate;
}

uint32_t getATMsgSize()
{
  xSemaphoreTake(command_list_samap, portMAX_DELAY);
  uint32_t restate = serial_at.size();
  xSemaphoreGive(command_list_samap);
  return restate;
}
String ReadMsgstr(uint32_t number)
{
  xSemaphoreTake(command_list_samap, portMAX_DELAY);
  String restate = serial_at[number].read_str;
  xSemaphoreGive(command_list_samap);
  return restate;
}

bool EraseFirstMsg()
{
  xSemaphoreTake(command_list_samap, portMAX_DELAY);
  serial_at.erase(serial_at.begin());
  xSemaphoreGive(command_list_samap);
  return true;
}

uint16_t GetstrNumber( String Str, uint32_t* ptrbuff )
{
  uint16_t count = 0;
  String Numberstr;
  int  indexpos = 0;
  while( Str.length() > 0 )
  {
    indexpos = Str.indexOf(",");
    if( indexpos != -1 )
    {
      Numberstr = Str.substring(0,Str.indexOf(","));
      Str = Str.substring(Str.indexOf(",")+1,Str.length());
      ptrbuff[count] = Numberstr.toInt();
      count ++;
    }
    else
    {
      ptrbuff[count] = Str.toInt();
      count ++;
      break;
    }
  }
  return count;
}
vector<String> restr_v;
uint16_t GetstrNumber( String StartStr,String EndStr,String Str )
{
  uint16_t count = 0;
  String Numberstr;
  int  indexpos = 0;

  Str = Str.substring(Str.indexOf(StartStr) + StartStr.length(), Str.indexOf(EndStr));
  Str.trim();
  restr_v.clear();
  
  while( Str.length() > 0 )
  {
    indexpos = Str.indexOf(",");
    if( indexpos != -1 )
    {
      Numberstr = Str.substring(0,Str.indexOf(","));
      Str = Str.substring(Str.indexOf(",")+1,Str.length());
      restr_v.push_back(Numberstr);
      count ++;
    }
    else
    {
      restr_v.push_back(Numberstr);;
      count ++;
      break;
    }
  }
  return count;
}

String getReString( uint16_t Number )
{
  if( restr_v.empty())
  {
    return String("");
  }
  return restr_v.at(Number);
}

uint16_t GetstrNumber( String StartStr,String EndStr,String Str, uint32_t* ptrbuff )
{
  uint16_t count = 0;
  String Numberstr;
  int  indexpos = 0;

  Str = Str.substring(Str.indexOf(StartStr) + StartStr.length(), Str.indexOf(EndStr));
  Str.trim();
  
  while( Str.length() > 0 )
  {
    indexpos = Str.indexOf(",");
    if( indexpos != -1 )
    {
      Numberstr = Str.substring(0,Str.indexOf(","));
      Str = Str.substring(Str.indexOf(",")+1,Str.length());
      ptrbuff[count] = Numberstr.toInt();
      count ++;
    }
    else
    {
      ptrbuff[count] = Str.toInt();
      count ++;
      break;
    }
  }
  return count;
}
uint32_t numberbuff[128];
String readstr;


void setup()
{
  M5.begin(true,true,true,true,kMBusModeInput);
/*   kMBusModeOutput,powered by USB or Battery
  kMBusModeInput,powered by outside input need to fill in this Otherwise M5Core2 will not work properly
  由外部供电时此项必填,否则M5Core2将无法正常工作 */
  
  Serial2.begin(115200, SERIAL_8N1, 13, 14);
/* 	Serial2.begin(115200, SERIAL_8N1, 13, 14);
    The 13(RX), 14(TX) pins of the CORE2 correspond to the 16(RX), 17(TX) pins of the COMX
    CORE2的13（RX）、14（TX）引脚对应COMX的16（RX）、17（TX）引脚
    Please make sure that the dialing switch of COMX is set to 16(RX), 17(TX).
    请确保 COMX 的拨号开关设置为 16(RX)、17(TX)。
 */
  Disbuff.createSprite(320,20);
  Disbuff.fillRect(0,0,320,20,BLACK);
  Disbuff.drawRect(0,0,320,20,Disbuff.color565(36,36,36));
  Disbuff.pushSprite(0,0);

  TerminalBuff.createSprite(120,220);
  TerminalBuff.fillRect(0,0,120,220,BLACK);
  TerminalBuff.drawRect(0,0,120,220,Disbuff.color565(36,36,36));
  TerminalBuff.pushSprite(0,20);
  terminal.setGeometry(0,20,120,220);
    

  pinMode(2, OUTPUT);
  digitalWrite(2, 0);

  Disbuff.setTextColor(WHITE);
  Disbuff.setTextSize(1);
  for (int i = 0; i < 100; i++ )
  { 
    Disbuff.fillRect(0,0,320,20,Disbuff.color565(36,36,36));
    Disbuff.pushSprite(0,0);
    Disbuff.setCursor(7,7);
    Disbuff.printf("Reset Module %02d",i);
    Disbuff.pushSprite(0,0);
    delay(10);
  }
  digitalWrite(2, 1);

  xTaskCreate(SIM800Task, "LTEModuleTask", 1024 * 2, (void *)0, 4, &xhandle_lte_event);
  command_list_samap = xSemaphoreCreateMutex();
  xSemaphoreGive(command_list_samap);
  
}
  
uint8_t restate;
void loop()
{

  AddMsg("AT+CSQ\r\n", kQUERY_MT, 1000, 1000);
  while ((readSendState(0) == kSendReady) || (readSendState(0) == kSending) || (readSendState(0) == kWaitforMsg))delay(50);
  restate = readSendState(0);
  readstr = ReadMsgstr(0).c_str();
  EraseFirstMsg();

  terminal.print(readstr);

  AddMsg("AT+CREG?\r\n", kQUERY_MT, 1000, 1000);
  while ((readSendState(0) == kSendReady) || (readSendState(0) == kSending) || (readSendState(0) == kWaitforMsg))delay(50);
  restate = readSendState(0);
  readstr = ReadMsgstr(0).c_str();
  EraseFirstMsg();
    
  terminal.print(readstr);

  delay(500);
  M5.update();

  // put your main code here, to run repeatedly:
}
